import tkinter as tk
from tkinter import ttk, messagebox, filedialog, scrolledtext
import requests
import json
import re
import os
from PIL import Image, ImageTk
import cairosvg
import io
import threading
from svg_gallery import SVGGallery

class SVGCreator:
    def __init__(self, root):
        self.root = root
        self.root.title("SVG图标生成器")
        self.root.geometry("1200x700")
        
        # 配置文件路径
        self.config_file = "config.json"
        self.mock_data_file = "mock_data.json"
        self.api_key = self.load_api_key()
        self.mock_svg_icons = self.load_mock_data()
        
        # SVG结果存储
        self.svg_results = []
        
        # 模拟模式状态 - 默认启用
        self.simulation_mode = True
        
        # 初始化图库
        self.gallery = SVGGallery(self.root)
        
        self.setup_ui()
        self.setup_menu()
        
    def load_api_key(self):
        """从配置文件加载API密钥"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    return config.get('api_key', '')
        except:
            pass
        return ''
    
    def save_api_key(self):
        """保存API密钥到配置文件"""
        config = {'api_key': self.api_key}
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败: {str(e)}")
    
    def load_mock_data(self):
        """从配置文件加载模拟数据"""
        try:
            if os.path.exists(self.mock_data_file):
                with open(self.mock_data_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    return data.get('mock_svg_icons', [])
        except Exception as e:
            print(f"加载模拟数据失败: {str(e)}")
        
        # 如果加载失败，返回默认数据
        return [
            "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n    <path fill=\"currentColor\" d=\"M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z\"/>\n</svg>",
            "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n    <path fill=\"currentColor\" d=\"M12 3l8 6v12h-5v-7H9v7H4V9l8-6z\"/>\n</svg>",
            "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\">\n    <path fill=\"currentColor\" d=\"M12 5.69l5 4.5V18h-2v-6H9v6H7v-7.81l5-4.5M12 3L2 12h3v8h6v-6h2v6h6v-8h3L12 3z\"/>\n</svg>"
        ]
    
    def setup_menu(self):
        """设置菜单栏"""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # File 菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="API Key 设置", command=self.open_api_key_dialog)
        file_menu.add_command(label="图库", command=self.gallery.open_gallery)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        
        # 帮助菜单
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="关于", command=self.show_about)
    
    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=2)  # 右侧结果区域更宽
        main_frame.rowconfigure(0, weight=1)
        

        
        # 左侧输入区域
        left_frame = ttk.LabelFrame(main_frame, text="📝 输入区域", padding="15", relief="solid", borderwidth=2)
        left_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 10))
        left_frame.columnconfigure(0, weight=1)
        
        # 指令输入
        ttk.Label(left_frame, text="SVG图标描述:").grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
        
        # 多行文本输入框
        self.prompt_text = scrolledtext.ScrolledText(left_frame, height=6, wrap=tk.WORD)
        self.prompt_text.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
        
        # 数量选择框
        quantity_frame = ttk.Frame(left_frame)
        quantity_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Label(quantity_frame, text="生成数量:").pack(side=tk.LEFT)
        self.quantity_var = tk.IntVar(value=5)
        quantity_spinbox = ttk.Spinbox(
            quantity_frame, 
            from_=1, 
            to=20, 
            textvariable=self.quantity_var,
            width=10,
            state="readonly"
        )
        quantity_spinbox.pack(side=tk.LEFT, padx=(5, 0))
        
        # 生成按钮
        self.generate_btn = ttk.Button(left_frame, text="生成SVG图标", command=self.generate_svg)
        self.generate_btn.grid(row=3, column=0, pady=(0, 10))
        
        # 进度条
        self.progress = ttk.Progressbar(left_frame, mode='indeterminate')
        self.progress.grid(row=4, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
        
        # 右侧结果显示区域
        result_frame = ttk.LabelFrame(main_frame, text="🎨 生成结果", padding="10", relief="solid", borderwidth=2)
        result_frame.grid(row=0, column=1, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(10, 0))
        result_frame.columnconfigure(0, weight=1)
        result_frame.rowconfigure(0, weight=1)
        
        # 创建滚动画布
        self.canvas = tk.Canvas(result_frame, bg='white')
        scrollbar_v = ttk.Scrollbar(result_frame, orient="vertical", command=self.canvas.yview)
        scrollbar_h = ttk.Scrollbar(result_frame, orient="horizontal", command=self.canvas.xview)
        self.scrollable_frame = ttk.Frame(self.canvas)
        
        # 绑定配置事件，确保scrollable_frame宽度跟随canvas宽度
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )
        
        # 绑定canvas宽度变化事件，让scrollable_frame宽度跟随
        self.canvas.bind(
            "<Configure>",
            lambda e: self.canvas.itemconfig(self.canvas_window, width=e.width)
        )
        
        self.canvas_window = self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=scrollbar_v.set, xscrollcommand=scrollbar_h.set)
        
        self.canvas.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar_v.grid(row=0, column=1, sticky=(tk.N, tk.S))
        scrollbar_h.grid(row=1, column=0, sticky=(tk.W, tk.E))
        
        # 绑定鼠标滚轮事件
        self.canvas.bind("<MouseWheel>", self._on_mousewheel)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(10, 0))
    
    def _on_mousewheel(self, event):
        """处理鼠标滚轮事件"""
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
    
    def toggle_simulation_mode(self):
        """切换模拟模式"""
        self.simulation_mode = self.simulation_var.get()
        if self.simulation_mode:
            self.status_var.set("已启用模拟模式")
        else:
            self.status_var.set("已关闭模拟模式")
    
    def open_api_key_dialog(self):
        """打开API Key设置对话框"""
        dialog = tk.Toplevel(self.root)
        dialog.title("配置设置")
        dialog.geometry("500x350")
        dialog.resizable(False, False)
        dialog.transient(self.root)
        dialog.grab_set()
        
        # 居中显示
        dialog.geometry("+%d+%d" % (self.root.winfo_rootx() + 50, self.root.winfo_rooty() + 50))
        
        # 主框架
        main_frame = ttk.Frame(dialog, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # API Key设置区域
        api_frame = ttk.LabelFrame(main_frame, text="API Key 设置", padding="15")
        api_frame.pack(fill=tk.X, pady=(0, 15))
        
        ttk.Label(api_frame, text="请输入您的 DeepSeek API Key:", font=("", 10)).pack(pady=(0, 5))
        ttk.Label(api_frame, text="您可以在 https://platform.deepseek.com 获取API Key", 
                 foreground="gray", font=("", 9)).pack(pady=(0, 10))
        
        # API Key输入
        api_key_var = tk.StringVar(value=self.api_key)
        api_key_entry = ttk.Entry(api_frame, textvariable=api_key_var, show="*", width=60)
        api_key_entry.pack(pady=(0, 10))
        api_key_entry.focus()
        
        # 模拟模式设置区域
        mode_frame = ttk.LabelFrame(main_frame, text="运行模式", padding="15")
        mode_frame.pack(fill=tk.X, pady=(0, 15))
        
        simulation_var = tk.BooleanVar(value=self.simulation_mode)
        simulation_check = ttk.Checkbutton(
            mode_frame, 
            text="启用模拟模式（使用预设的示例SVG，无需API Key）", 
            variable=simulation_var
        )
        simulation_check.pack(anchor=tk.W)
        
        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.pack()
        
        def save_and_close():
            new_key = api_key_var.get().strip()
            new_simulation_mode = simulation_var.get()
            
            # 如果不是模拟模式且API Key为空，则提示
            if not new_simulation_mode and not new_key:
                messagebox.showwarning("警告", "请输入有效的API密钥或启用模拟模式")
                return
            
            self.api_key = new_key
            self.simulation_mode = new_simulation_mode
            self.save_api_key()
            
            # 更新状态显示
            if self.simulation_mode:
                self.status_var.set("已启用模拟模式")
            else:
                self.status_var.set("已设置API密钥")
            
            messagebox.showinfo("成功", "配置已保存")
            dialog.destroy()
        
        def cancel():
            dialog.destroy()
        
        ttk.Button(button_frame, text="保存", command=save_and_close).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="取消", command=cancel).pack(side=tk.LEFT)
        
        # 键盘快捷键
        dialog.bind('<Return>', lambda e: save_and_close())
        dialog.bind('<Escape>', lambda e: cancel())
    
    def show_about(self):
        """显示关于对话框"""
        messagebox.showinfo("关于", 
                           "SVG图标生成器 v1.0\n\n"
                           "使用DeepSeek API生成SVG图标\n"
                           "支持模拟模式进行测试\n\n"
                           "© 2024")
    
    def save_api_key_handler(self):
        """保存API密钥处理器"""
        if not self.api_key:
            messagebox.showwarning("警告", "请输入有效的API密钥")
            return
        
        self.save_api_key()
        messagebox.showinfo("成功", "API密钥已保存")
    
    def generate_svg(self):
        """生成SVG图标"""
        prompt = self.prompt_text.get("1.0", tk.END).strip()
        if not prompt:
            messagebox.showwarning("警告", "请输入SVG图标描述")
            return
        
        quantity = self.quantity_var.get()
        
        # 构造发送给服务器的消息
        message = f"""我希望生成一个移动app上使用的图标文件，格式为svg，返回内容要将svg内容用svg标签包含起来。如
```svg
```
具体要求如下：
{prompt}
注意事项：
1.请不要生成html文件，要生成svg文件。
2.一共生成{quantity}个图标，每个图标放在一个svg标签里。"""
        
        # 在控制台打印待发送的消息
        print("=== 待发送的消息 ===")
        print(message)
        print("==================")
        
        # 检查是否为模拟模式
        if self.simulation_mode:
            self.generate_btn.config(state='disabled')
            self.progress.start()
            self.status_var.set("模拟模式：正在生成SVG图标...")
            
            # 在新线程中执行模拟响应
            thread = threading.Thread(target=self._simulate_response, args=(message, quantity))
            thread.daemon = True
            thread.start()
            return
        
        # 正常模式需要API密钥
        if not self.api_key.strip():
            messagebox.showwarning("警告", "请先通过菜单设置DeepSeek API密钥或启用模拟模式")
            return
        
        # 在新线程中执行API调用
        self.generate_btn.config(state='disabled')
        self.progress.start()
        self.status_var.set("正在生成SVG图标...")
        
        thread = threading.Thread(target=self._generate_svg_thread, args=(message, quantity))
        thread.daemon = True
        thread.start()
    
    def _simulate_response(self, message, quantity):
        """模拟服务器响应"""
        try:
            # 模拟网络延迟
            import time
            time.sleep(1)
            
            # 从配置文件读取模拟SVG数据，根据数量重复或截取
            mock_svgs = self.mock_svg_icons.copy()
            
            # 根据请求数量调整返回的SVG数量
            if quantity <= len(mock_svgs):
                result_svgs = mock_svgs[:quantity]
            else:
                # 如果请求数量超过预设数量，循环使用
                result_svgs = []
                for i in range(quantity):
                    result_svgs.append(mock_svgs[i % len(mock_svgs)])
            
            # 显示结果
            self.root.after(0, self._display_results, result_svgs)
            
        except Exception as e:
            self.root.after(0, self._show_error, f"模拟响应失败: {str(e)}")
        finally:
            self.root.after(0, self._reset_ui)
    
    def _generate_svg_thread(self, message, quantity):
        """在线程中生成SVG"""
        try:
            # 构建请求
            url = "https://api.deepseek.com/v1/chat/completions"
            headers = {
                "Authorization": f"Bearer {self.api_key.strip()}",
                "Content-Type": "application/json"
            }
            
            data = {
                "model": "deepseek-chat",
                "messages": [
                    {
                        "role": "system",
                        "content": "你是一个专业的SVG图标设计师。请根据用户的描述生成相应的SVG图标代码。只返回SVG代码，不要包含其他解释文字。每个SVG图标都要用完整的<svg>标签包含。"
                    },
                    {
                        "role": "user",
                        "content": message
                    }
                ],
                "temperature": 0.7,
                "max_tokens": 4000
            }
            
            response = requests.post(url, headers=headers, json=data, timeout=30)
            
            if response.status_code == 200:
                result = response.json()
                content = result['choices'][0]['message']['content']
                
                # 提取SVG标签
                svg_pattern = r'<svg[^>]*>.*?</svg>'
                svg_matches = re.findall(svg_pattern, content, re.DOTALL | re.IGNORECASE)
                
                if svg_matches:
                    self.root.after(0, self._display_results, svg_matches)
                else:
                    self.root.after(0, self._show_error, "未找到有效的SVG代码")
            else:
                error_msg = f"API请求失败: {response.status_code}"
                try:
                    error_detail = response.json().get('error', {}).get('message', '')
                    if error_detail:
                        error_msg += f"\n{error_detail}"
                except:
                    pass
                self.root.after(0, self._show_error, error_msg)
                
        except requests.exceptions.Timeout:
            self.root.after(0, self._show_error, "请求超时，请检查网络连接")
        except requests.exceptions.RequestException as e:
            self.root.after(0, self._show_error, f"网络请求错误: {str(e)}")
        except Exception as e:
            self.root.after(0, self._show_error, f"生成失败: {str(e)}")
        finally:
            self.root.after(0, self._reset_ui)
    
    def _display_results(self, svg_list):
        """显示SVG结果"""
        # 清除之前的结果
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        
        # 配置scrollable_frame的列权重，让内容占满整行
        self.scrollable_frame.columnconfigure(0, weight=1)
        
        self.svg_results = svg_list
        
        # 显示每个SVG，每行一个
        for i, svg_code in enumerate(svg_list):
            try:
                # 创建框架容器，每行一个，占满整行宽度
                item_frame = ttk.LabelFrame(self.scrollable_frame, text=f"图标 {i+1}", padding="10")
                item_frame.grid(row=i, column=0, padx=5, pady=5, sticky=(tk.W, tk.E, tk.N, tk.S))
                item_frame.columnconfigure(1, weight=1)  # 让中间区域可扩展
                
                # 渲染SVG为图片
                try:
                    png_data = cairosvg.svg2png(bytestring=svg_code.encode('utf-8'))
                    image = Image.open(io.BytesIO(png_data))
                    
                    # 调整图片大小用于显示
                    display_size = (128, 128)
                    image.thumbnail(display_size, Image.Resampling.LANCZOS)
                    photo = ImageTk.PhotoImage(image)
                    
                    # 显示图片在左侧
                    img_label = ttk.Label(item_frame, image=photo)
                    img_label.image = photo  # 保持引用
                    img_label.grid(row=0, column=0, padx=(0, 10), pady=5, rowspan=2)
                    
                except Exception as e:
                    # 如果渲染失败，显示错误信息
                    error_label = ttk.Label(item_frame, text=f"渲染失败: {str(e)}")
                    error_label.grid(row=0, column=0, padx=(0, 10), pady=5, rowspan=2)
                
                # 保存SVG按钮，放在图标右侧
                save_btn = ttk.Button(
                    item_frame, 
                    text="保存SVG", 
                    command=lambda idx=i: self.save_svg(idx)
                )
                save_btn.grid(row=0, column=2, padx=(10, 0), pady=5, sticky=(tk.N, tk.S))
                
            except Exception as e:
                error_frame = ttk.LabelFrame(self.scrollable_frame, text=f"错误 {i+1}", padding="10")
                error_frame.grid(row=i//2, column=i%2, padx=5, pady=5)
                ttk.Label(error_frame, text=f"显示失败: {str(e)}").pack()
        
        self.status_var.set(f"成功生成 {len(svg_list)} 个SVG图标")
    
    def save_svg(self, index):
        """保存SVG文件"""
        if index >= len(self.svg_results):
            return
        
        filename = filedialog.asksaveasfilename(
            defaultextension=".svg",
            filetypes=[("SVG files", "*.svg"), ("All files", "*.*")],
            title="保存SVG文件"
        )
        
        if filename:
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(self.svg_results[index])
                messagebox.showinfo("成功", f"SVG文件已保存到: {filename}")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败: {str(e)}")
    
    def save_png(self, index):
        """保存PNG文件"""
        if index >= len(self.svg_results):
            return
        
        filename = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG files", "*.png"), ("All files", "*.*")],
            title="保存PNG文件"
        )
        
        if filename:
            try:
                png_data = cairosvg.svg2png(bytestring=self.svg_results[index].encode('utf-8'))
                with open(filename, 'wb') as f:
                    f.write(png_data)
                messagebox.showinfo("成功", f"PNG文件已保存到: {filename}")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败: {str(e)}")
    
    def _show_error(self, error_msg):
        """显示错误信息"""
        messagebox.showerror("错误", error_msg)
        self.status_var.set("生成失败")
    
    def _reset_ui(self):
        """重置UI状态"""
        self.progress.stop()
        self.generate_btn.config(state='normal')

def main():
    root = tk.Tk()
    app = SVGCreator(root)
    root.mainloop()

if __name__ == "__main__":
    main()